const redis = require('redis');
const genericPool = require('generic-pool');
const default_datasource = require('./DATA_SOURCE_CONFIG_JSON.json');

const defaultRedisConfig = {
}

const pool = {};

const opts = {
    max: 4,
    min: 4
};

function _getPool(redisConfig) {
    let poolKey = redisConfig.host + '_' + redisConfig.port + '_' + redisConfig.index;
    let cp = pool[poolKey];
    if (!cp) {
        cp = pool[poolKey] = genericPool.createPool(new Factory(redisConfig), opts);
        console.log('redis:', poolKey, 'init success')
    }
    return cp;
}

class Factory {
    constructor(redisConfig) {
        this.redisConfig = redisConfig;
    }

    create() {
        let client = redis.createClient(this.redisConfig.port, this.redisConfig.host, {
            retry_strategy: function (options) {
                if (options.error && options.error.code === "ECONNREFUSED") {
                    return 1000;
                }
                if (options.total_retry_time > 1000 * 60 * 60) {
                    return 1000;
                }
                if (options.attempt > 10) {
                    return 1000;
                }
                return Math.min(options.attempt * 100, 3000);
            },
        });
        client.on("error", function (err) {
            return new Promise((reject) => {
                reject(err);
            });
        });
        client.on("reconnecting", function () {
            console.log("redis reconnecting")
        });
        client.on("ready", function () {
            console.log("redis ready")
        });
        client.on("end", function () {
            console.log("redis end")
        });
        client.on("connect", function () {
            console.log("redis connect")
        });
        if (this.redisConfig.password != null && this.redisConfig.password != '') {
            client.auth(this.redisConfig.password, function (err) {
                if (err) {
                    return new Promise((reject) => {
                        reject(err);
                    });
                }
            });
        }
        client.select(this.redisConfig.index, function (err) {
            if (err) {
                return new Promise((reject) => {
                    reject(err);
                });
            }
        });
        return client;
    }

    destroy(client) {
        client.end();
    }
};

let redisGet = async (key, redisConfig = defaultRedisConfig) => {
    try {
        let result = await new Promise((resolve, reject) => {
            if (key == null || key == undefined || key == '') {
                reject(new Error('redis的key不能为null'));
            }
            let _pool;
            try {
                _pool = _getPool(redisConfig)
            } catch (e) {
                reject(e);
                return;
            }
            let acquire = _pool.acquire();
            acquire.then(function (client) {
                client.get(key, function (err, reply) {
                    if (err) {
                        reject(err);
                    } else {
                        resolve(reply);
                    }
                    _pool.release(client);
                });
            }).catch(function (err) {
                reject(err);
            });
        });
        return result;
    } catch (e) {
        throw e;
    }
}

let redisSet = async (key, value, ttl, redisConfig = defaultRedisConfig) => {
    try {
        let result = await new Promise((resolve, reject) => {

            if (key == null || key == undefined || key == '') {
                reject(new Error('redis的key不能为null'));
            }

            if (value == null || value == undefined || value == '') {
                reject(new Error('redis的value不能为null'));
            }

            let _pool;
            try {
                _pool = _getPool(redisConfig)
            } catch (e) {
                reject(e);
                return;
            }
            if (ttl && ttl > 0) {
                let acquire = _pool.acquire();
                acquire.then(function (client) {
                    client.setex(key, ttl, value, function (err, reply) {
                        if (err) {
                            reject(err);
                        } else {
                            resolve(reply);
                        }
                        _pool.release(client);
                    });
                }).catch(function (err) {
                    reject(err);
                });
            } else {
                let acquire = _pool.acquire();
                acquire.then(function (client) {
                    client.set(key, value, function (err, reply) {
                        if (err) {
                            reject(err);
                        } else {
                            resolve(reply);
                        }
                        _pool.release(client);
                    });
                }).catch(function (err) {
                    reject(err);
                });
            }
        });
        return result;
    } catch (e) {
        throw e;
    }
}

let redisDel = async (key, redisConfig = defaultRedisConfig) => {
    try {
        let result = await new Promise((resolve, reject) => {

            if (key == null || key == undefined || key == '') {
                reject(new Error('redis的key不能为null'));
            }

            let _pool;
            try {
                _pool = _getPool(redisConfig)
            } catch (e) {
                reject(e);
                return;
            }
            let acquire = _pool.acquire();
            acquire.then(function (client) {
                client.del(key, function (err, reply) {
                    if (err) {
                        reject(err);
                    } else {
                        resolve(true);
                    }
                    _pool.release(client);
                });
            }).catch(function (err) {
                reject(err);
            });
        });
        return result;
    } catch (e) {
        throw e;
    }
}

module.exports = {redisGet, redisSet, redisDel}